﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Drawing.Design;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.Design;
using JQuery.WebKit.Base;
using JQuery.WebKit.Common.Logging;
using JQuery.WebKit.Interfaces;
using JQuery.WebKit.Util;
using JQuery.WebKit.WebCommon;
using JQuery.WebKit.WebCommon.Security;

namespace JQuery.WebKit
{
    public class JPage : Page, IJPage
    {
        public Uri RequestUrl { get; set; }
        public WebScriptResourceCollection Resources { get; private set; }
        public event PipelineEventHandler PageSubmit;
        public event EventHandler PageRefresh;
        public event EventHandler PageLanded;

        private string _contextXml;
        [Category("Data"),
       UrlProperty("*.xml"),
       EditorAttribute(typeof(XmlDataFileEditor), typeof(UITypeEditor))]
        public string ContextXml
        {
            get
            {
                if (this.Master != null)
                {
                    _contextXml = this.Master.ContextXml;
                    return _contextXml;
                }
                return _contextXml;
            }
            set
            {
                _contextXml = value;
                if (this.Master != null)
                {
                    this.Master.ContextXml = _contextXml;
                }
            }
        }

        public Uri Url
        {
            get { return JUtil.GetPageUri(); }
        }

        public NameValueCollection QueryString
        {
            get { return JUtil.GetPageQueryString(); }
        }

        public string Name { get; set; }

        public new JPage Page
        {
            get { return base.Page as JPage; }
        }

        public Hashtable PageData
        {
            get
            {
                Hashtable data = HttpContext.Current.Items["PageData"] as Hashtable;
                if (data == null)
                {
                    data = new Hashtable();
                }
                return data;
            }
        }

        public Uri RedirectUrl
        {
            get
            {
                Uri url = HttpContext.Current.Items["RedirectUrl"] as Uri;
                if (url == null)
                {
                    //url = Page.Url;
                }
                return url;
            }
            set
            {
                HttpContext.Current.Items["RedirectUrl"] = value;
            }
        }

        public new bool IsPostBack
        {
            get { return HttpContext.Current != null ? Convert.ToBoolean(HttpContext.Current.Items["IsPostBack"]) == true : false; }
        }

        public bool IsRefresh
        {
            get { return HttpContext.Current != null ? Convert.ToBoolean(HttpContext.Current.Items["IsRefresh"]) == true : false; }
        }

        public new JMasterPage Master
        {
            get { return base.Master as JMasterPage; }
        }

        public new JForm Form
        {
            get { return base.Form != null ? base.Form as JForm : (this.Master != null ? this.Master.Form as JForm : null); }
        }

        public JPage()
        {
            Resources = new WebScriptResourceCollection(this as IJPage);
        }

        public ISecurityPrincipal Authentication
        {
            get
            {
                return HttpContext.Current.Session["Authentication"] as ISecurityPrincipal;
            }
        }

        private static void SetPageData()
        {
            Hashtable dataCollection = JUtil.GetRequestJSONCollection();
            HttpContext.Current.Items["PageData"] = dataCollection;
        }

        [WebMethod(EnableSession = true)]
        public static string SetPostBackData()
        {
            try
            {
                JPage currentPage = HttpContext.Current.Handler as JPage;

                if (currentPage == null)
                {
                    throw new ArgumentNullException("Page is not a JPage.");
                }
                HttpContext.Current.Items["IsPostBack"] = true;

                return Refresh(null);
            }
            catch (Exception ex)
            {
                return string.Format("<span>{0}</span>", ex);
            }
        }

        [WebMethod(EnableSession = true)]
        public static string Refresh()
        {
            return Refresh(null);
        }

        private static string Refresh(string path)
        {
            try
            {
                JPage currentPage = HttpContext.Current.Handler as JPage;
                //System.Threading.Thread.Sleep(2000);
                if (currentPage == null)
                {
                    return string.Empty;
                }
                if (currentPage.RequestUrl == null)
                {
                    currentPage.RequestUrl = new Uri(JUtil.GetBasePath());
                }
                SetPageData();

                HttpContext.Current.Items["IsRefresh"] = true;
                string localPath = JUtil.GetPageUri().LocalPath;//.PathAndQuery;//.MakeRelativeUri(currentPage._requestUrl).ToString();
                if (string.IsNullOrEmpty(localPath))
                {
                    localPath = (string)HttpContext.Current.Request.ServerVariables["URL"];
                }
                StringWriter stringWriter = new StringWriter();
                using (Html32TextWriter writer = new Html32TextWriter(stringWriter))
                {
                    HttpContext.Current.Server.Execute(localPath, writer, true);
                }
                if (currentPage.RedirectUrl != null)// (string)HttpContext.Current.Request.ServerVariables["URL"] != localPath)
                {
                    return string.Format("location={0}", currentPage.RedirectUrl);
                }
                return stringWriter.ToString();
            }
            catch (Exception ex)
            {
                return string.Format("<span>{0}</span>", ex);
            }
        }

        protected override void OnPreInit(EventArgs e)
        {
            base.OnPreInit(e);
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            this.Error += new EventHandler(JPage_Error);
        }

        void JPage_Error(object sender, EventArgs e)
        {
            if (this.Form == null || string.IsNullOrEmpty(this.Form.ErrorContainerID))
            {
                return;
            }
            Control errorCtrl = this.FindControlRecursive(this.Form.ErrorContainerID, IDType.Server);
            if (errorCtrl as AeroWindow == null)
            {
                return;
            }

            Exception ex = Server.GetLastError();
            if (ex == null)
            {
                return;
            }
            Exception innerEx = ex.InnerException;
            while (innerEx != null)
            {
                ex = innerEx;
                innerEx = innerEx.InnerException;
            }

            LogManager.LogErrorFormat("Page {0} thrown an error: {1} ", this.Name, ex);

            AeroWindow errorWindow = (errorCtrl as AeroWindow);
            errorWindow.Controls.Add(new LiteralControl(ex.ToString()));
            errorWindow.AutoOpen = true;
            Server.ClearError();
        }

        public virtual void OnPageLanded()
        {
            if (PageLanded != null)
            {
                PageLanded(this, EventArgs.Empty);
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);
            EnsureChildControls();
            if (!this.IsPostBack && !this.IsRefresh)
            {
                if (this.GetChildren<WebGrid>(item => item.IsGridRequest()).Count == 0)
                {
                    OnPageLanded();
                }
            }

            List<JUpdater> panelList = this.GetChildren<JUpdater>();
            panelList.ForEach(item => item.OnLoad());

            if (IsRefresh && !IsPostBack)
            {
                OnRefresh();
            }
            else if (IsPostBack)
            {
                OnSubmit();
            }
        }

        public virtual void OnSubmit()
        {
            this.EnsureChildControls();
            string updaterId = (string)PageData["target"];
            if (string.IsNullOrEmpty(updaterId))
            {
                return;
            }

            JUpdater pnl = (JUpdater)this.FindControlRecursive(updaterId, IDType.Client);
            Control sender = null;
            if (pnl != null)
            {
                string senderId = (string)this.PageData["sender"];
                if (!string.IsNullOrEmpty(senderId))
                {
                    sender = pnl.FindControlRecursive(senderId, IDType.Client);
                }
                SetPostData(pnl);
                pnl.OnSubmit(sender);
            }
            if (PageSubmit != null)
            {
                PageSubmit(this, new PipelineEventArgs(sender));
            }
        }

        public virtual void OnRefresh()
        {
            this.EnsureChildControls();
            string updaterId = (string)PageData["target"];
            if (string.IsNullOrEmpty(updaterId))
            {
                return;
            }

            JUpdater pnl = (JUpdater)this.FindControlRecursive(updaterId, IDType.Client);
            Control sender = null;
            if (pnl != null)
            {
                string senderId = (string)this.PageData["sender"];
                if (!string.IsNullOrEmpty(senderId))
                {
                    sender = pnl.FindControlRecursive(senderId, IDType.Client);
                }
                SetPostData(pnl);
                pnl.OnRefresh(sender);
            }
            if (PageRefresh != null)
            {
                PageRefresh(this, EventArgs.Empty);
            }
        }

        public void SetPostData(JUpdater parent)
        {
            this.EnsureChildControls();
            List<JControl> ctrlList = parent.GetChildren<JControl>();

            foreach (JControl ctrl in ctrlList)
            {
                if (ctrl is JImage)
                {
                    continue; //image has it's own value processing
                }
                else if (ctrl is IKeyTextPair && Page.PageData[ctrl.ClientID] is IDictionary)
                {
                    Dictionary<object, object> dct = Page.PageData[ctrl.ClientID] as Dictionary<object, object>;
                    if (dct.Count == 1)
                    {
                        KeyValuePair<object, object> kv = dct.First();

                        (ctrl as IKeyTextPair).Key = kv.Key;
                        (ctrl as IKeyTextPair).Text = kv.Value;
                    }
                }
                else if (ctrl is IKeyTextPair && Page.PageData[ctrl.ClientID] is KeyValuePair<object, object>)
                {
                    KeyValuePair<object, object>? kv = Page.PageData[ctrl.ClientID] as KeyValuePair<object, object>?;

                    (ctrl as IKeyTextPair).Key = kv.Value.Key;
                    (ctrl as IKeyTextPair).Text = kv.Value.Value;
                }
                else
                {
                    ctrl.Value = Page.PageData[ctrl.ClientID];
                }
            }
        }

        public void AddJQueryPlugin(JPluginEnum plugin)
        {
            this.Resources.Add(new WebScriptResource(typeof(JPage), this.ClientID, ResourceType.Javascript, Globals.ResourcePaths.JQueryLibraries.JQuery));
            switch (plugin)
            {
                case JPluginEnum.JQueryShadow:
                    this.Resources.Add(CommonResources.JQueryShadow);
                    break;
                case JPluginEnum.JQueryEasing:
                    this.Resources.Add(CommonResources.JQueryEasing);
                    break;
                case JPluginEnum.JQueryCookie:
                    this.Resources.Add(CommonResources.JQueryCookie);
                    break;
                case JPluginEnum.JQueryEvenHidden:
                    this.Resources.Add(CommonResources.JQueryEvenHidden);
                    break;
                case JPluginEnum.JQueryFormat:
                    this.Resources.Add(CommonResources.JQueryFormat);
                    break;
                case JPluginEnum.JQueryStopWatch:
                    this.Resources.Add(CommonResources.JQueryStopWatch);
                    break;
                default:
                    break;
            }
        }

        public void Redirect(string uriString)
        {
            if (Page.IsPostBack || Page.IsRefresh)
            {
                RedirectUrl = new Uri(new Uri(string.Format("{0}://{1}", HttpContext.Current.Request.Url.Scheme, HttpContext.Current.Request.Url.Authority)), uriString);
            }
            else
            {
                Page.Response.Redirect(uriString);
            }
        }

        public void Reload()
        {
            this.Redirect(this.Url.ToString());
        }

        protected override void OnPreRender(EventArgs e)
        {
            this.Resources.Add(CommonResources.JQueryCustom);
            base.OnPreRender(e);
        }

        protected override void Render(HtmlTextWriter writer)
        {
            if (HttpContext.Current.Session["JSON"] == null)
            {
                string id = (string)PageData["target"];
                if (!string.IsNullOrEmpty(id))
                {
                    JUpdater pnl = (JUpdater)this.FindControlRecursive(id, IDType.Client);
                    if (pnl != null)
                    {
                        pnl.RenderBaseControl(writer);//pnl.RenderBaseControlChildren(writer);//.RenderControl(writer);
                    }
                }
                else
                {
                    base.Render(writer);
                }
            }
            else
            {
                writer.Write(HttpContext.Current.Session["JSON"].ToString());
            }
        }

        public Control FindControlRecursive(string id, IDType idType)
        {
            return HtmlUtil.FindControlRecursive(this, id, idType);
        }


    }
}
